/**
  ******************************************************************************
  * @author     Chris
  * @since      2024/6/12 10:55
  *
  * @file       pd_gpio.c
  * @brief      GPIO peripheral driver.
  *
  * @note       This file contains the peripheral driver for the GPIO.
  *
  ******************************************************************************
  * Change Logs:
  *   Date           Author       Notes
  *   2024-06-12     Chris        the first version
  *
  ******************************************************************************
  */

#include <stm32f4xx_ll_gpio.h>
#include <stm32f4xx_ll_bus.h>
#include "pd_gpio.h"

static void GPIO_init_(const GPIO *this) {
    LL_GPIO_InitTypeDef GPIO_InitStruct;

    if      (this->GPIOx == GPIOA) LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
    else if (this->GPIOx == GPIOB) LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
    else if (this->GPIOx == GPIOC) LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC);
    else if (this->GPIOx == GPIOD) LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOD);
    else if (this->GPIOx == GPIOE) LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOE);
    else if (this->GPIOx == GPIOF) LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOF);

    GPIO_InitStruct.Pin        = this->Pin;
    GPIO_InitStruct.Mode       = this->Mode;
    GPIO_InitStruct.Speed      = this->Speed;
    GPIO_InitStruct.OutputType = this->OutputType;
    GPIO_InitStruct.Pull       = this->Pull;
    GPIO_InitStruct.Alternate  = this->Alternate;
    LL_GPIO_Init(this->GPIOx, &GPIO_InitStruct);
}

uint8_t GPIO_get_(const GPIO *this) {
    return (this->GPIOx->IDR & this->Pin) == 0 ? 0 : 1;
}

void GPIO_set_(const GPIO *this) {
    this->GPIOx->BSRR = this->Pin;
}

void GPIO_reset_(const GPIO *this) {
    this->GPIOx->BSRR = this->Pin << 16;
}

void GPIO_setOutMode_(const GPIO *this) {
    LL_GPIO_SetPinMode(this->GPIOx, this->Pin, LL_GPIO_MODE_OUTPUT);
}

void GPIO_setInMode_(const GPIO *this) {
    LL_GPIO_SetPinMode(this->GPIOx, this->Pin, LL_GPIO_MODE_INPUT);
}

void GPIO_constructor(GPIO *this, GPIO_TypeDef *GPIOx, const uint32_t Pin) {
    static struct GPIOVtbl vtbl = {
        .init         = &GPIO_init_,
        .get          = &GPIO_get_,
        .set          = &GPIO_set_,
        .reset        = &GPIO_reset_,
        .set_out_mode = &GPIO_setOutMode_,
        .set_in_mode  = &GPIO_setInMode_,
    };

    this->vptr = &vtbl;

    this->GPIOx      = GPIOx;
    this->Pin        = Pin;
    this->Pull       = LL_GPIO_PULL_UP;
    this->Mode       = LL_GPIO_MODE_OUTPUT;
    this->Speed      = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    this->OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    this->Alternate  = LL_GPIO_AF_0;
}

static void GPIOList_init_(const GPIOList *this) {
}

void GPIOList_constructor(GPIOList *this, GPIO *gpios, const uint8_t gpioSize) {
    static struct GPIOListVtbl vtbl = {
        .init = &GPIOList_init_,
    };

    this->vptr = &vtbl;
    this->gpios = gpios;
    this->gpioSize = gpioSize;
}
